﻿// Referens https://code.google.com/p/1dv437arkanoid/source/browse/trunk/Collisions/Collisions2/Model/Level.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace Santa_sAdventure.Model
{
    class Level
    {
        // Number of bricks x, y
        internal const int m_levelWidth = 20;
        internal const int m_levelHeight = 20;
        // Brick types
        private char m_solidChar = 'x';
        private char m_playerStartPositionChar = 's';
        private char m_exitChar = 'e';
        private char m_movingEnemyChar = 'm';
        private char m_shootingEnemyRightChar = 'b';
        private char m_shootingEnemyLeftChar = 'd';
        private char m_packetChar = 'p';
        private char m_trapChar = 't';
        // Wich level
        private string m_levelString;
        private int m_levelIndex;
        // Collecion of all the tiles in the level
        internal Tile[,] m_tiles = new Tile[m_levelWidth, m_levelHeight];
        // Player and exit position
        private Vector2 m_playerStartPosition = Vector2.Zero;
        private Vector2 m_exitPosition = Vector2.Zero;
        // Packets
        private List<Packets> m_packetsList;
        // Enemies
        private List<Enemy> m_enemyList;
        // Enemy creator
        private EnemyFacory m_enemyFactory;
        // Content
        private ContentManager m_content;
        // How many packets the player have picked up in the level
        private int m_packetsTaken;
        private int m_enemiesKilled;
        // Total time level have been played
        private float m_totaltime;
        // Helptext
        private string[,] m_helpText;

        // Constructor
        internal Level(string a_levelString, ContentManager a_content, int a_levelIndex)
        {
            m_levelString = a_levelString;
            m_levelIndex = a_levelIndex;
            m_enemyFactory = new EnemyFacory();
            m_content = a_content;
            m_enemyList = new List<Enemy>();
            m_packetsList = new List<Packets>();
            IsCompleted = false;
            // Generate level
            GenerateLevel();
            // Generate help text
            GenerateHelpText();
        }

        // Level width
        internal int Width{ get { return m_levelWidth; } }

        // Level height
        internal int Height { get { return m_levelHeight; } }

        // Genrate help text for levels
        private void GenerateHelpText()
        {
            m_helpText = new string[4, 1] {{"Use arrow keys to move and jump. \"P\" to pause."},
                                           {"Watch out for enemies. Jump on them to kill them and get a jump boost.\nCollect packets to get more points.\nKilling enemies also grants more points."}, 
                                           {"Step on traps and you will die a terrible death."}, 
                                           {"Some enemies can shoot, watch out! \nProtip: You can jump on bullets."} };
        }

        // Returns a string containing help
        internal string GetHelpText()
        {
            if (m_levelIndex > m_helpText.Length - 1)
            {
                return "";
            }
            return m_helpText[m_levelIndex, 0];
        }

        // Generate a level from a string
        private void GenerateLevel()
        {
            for (int x = 0; x < m_levelWidth; x++)
            {
                for (int y = 0; y < m_levelHeight; y++)
                {
                    /* Examlpe 2:nd row, sign nr 5 = 1 * 10 + 5 = sign nr 15 in string */
                    int index = y * m_levelWidth + x;

                    if (m_levelString[index] == m_solidChar)
                    {
                        m_tiles[x, y] = Tile.CreateSolid();
                    }
                    else if (m_levelString[index] == m_trapChar)
                    {
                        m_tiles[x, y] = Tile.CreateTrap();
                    }
                    else if (m_levelString[index] == m_playerStartPositionChar)
	                {
                        PlayerStartPosition = new Vector2(x, y-1);
                        m_tiles[x, y] = Tile.CreatePassable();
	                }
                    else if (m_levelString[index] == m_exitChar)
                    {
                        ExitPosition = new Vector2(x, y);
                        m_tiles[x, y] = Tile.CreatePassable();
                    }
                    else if (m_levelString[index] == m_movingEnemyChar)
                    {
                        m_enemyList.Add(m_enemyFactory.MakeMovingEnemy(x,y - 1, m_content));
                        m_tiles[x, y] = Tile.CreatePassable();
                    }
                    else if (m_levelString[index] == m_shootingEnemyRightChar)
                    {
                        m_enemyList.Add(m_enemyFactory.MakeShootingEnemy(x,y -1, m_content,1));
                        m_tiles[x, y] = Tile.CreatePassable();
                    }
                    else if (m_levelString[index] == m_shootingEnemyLeftChar)
                    {
                        m_enemyList.Add(m_enemyFactory.MakeShootingEnemy(x, y -1, m_content, -1));
                        m_tiles[x, y] = Tile.CreatePassable();
                    }
                    else if (m_levelString[index] == m_packetChar)
                    {
                        m_packetsList.Add(new Packets(x, y));
                        m_tiles[x, y] = Tile.CreatePassable();
                    }
                    else
                    {
                        m_tiles[x, y] = Tile.CreatePassable();
                    }
                }
            }
        }

        // Remove content in level
        internal void Dispose()
        {
            m_tiles = new Tile[m_levelWidth, m_levelHeight];
            PlayerStartPosition = Vector2.Zero;
            ExitPosition = Vector2.Zero;
            m_packetsList.Clear();
        }

        // Return level tiles
        internal Tile[,] GetTiles()
        {
            return m_tiles;
        }

        // Get player start position
        internal Vector2 PlayerStartPosition
        {
            get { return m_playerStartPosition; }
            set { m_playerStartPosition = value; }
        }

        // Get player start position
        internal Vector2 ExitPosition
        {
            get { return m_exitPosition; }
            set { m_exitPosition = value; }
        }

        // Update the level elements
        internal void Update(float a_totalSeconds)
        {
            m_totaltime += a_totalSeconds;


            for (int i = 0; i < m_enemyList.Count; i++)
            {
                if (!m_enemyList[i].IsDead)
                {
                    m_enemyList[i].Update(a_totalSeconds);
                }
                if (m_enemyList[i] is ShootingEnemy)
                {
                    (m_enemyList[i] as ShootingEnemy).UpdateBullets(a_totalSeconds);
                }
            }
        }

        // Returns all the enemies in the level
        internal List<Enemy> GetEnemies()
        {
            return m_enemyList;
        }

        // If the level is completed
        internal bool IsCompleted { get; set; }

        // Gets all the packets
        internal List<Packets> GetPackets()
        {
            return m_packetsList;
        }

        // Increase packet taken value
        internal void IncreasePacketsTaken()
        {
            m_packetsTaken++;
            if (m_packetsTaken > m_packetsList.Count)
            {
                throw new ApplicationException("Cannot have this many packets in this level");
            }
        }

        // Increase enemies killed value
        internal void IncreaseEnemiesKilled()
        {
            m_enemiesKilled++;
            if (m_enemiesKilled > m_enemyList.Count)
            {
                throw new ApplicationException("Cannot have this many enemies killed in this level");
            }
        }

        // Get number of packets taken
        internal int GetNumberOfPacketsTaken()
        {
            return m_packetsTaken;
        }

        // Get number of enemies killed
        internal int GetNumberOfEnemieKilled()
        {
            return m_enemiesKilled;
        }

        // Level Time elapsed
        internal float TimeElapsed { get { return m_totaltime; } }

        // Total score
        internal int TotalScore(Player a_player)
        {
            return GetNumberOfPacketsTaken() * 100 + a_player.NrOfLifes * 100 + GetNumberOfEnemieKilled() * 100;
        }
    }
}
